package com.gooseeker.modbus;

import org.apache.commons.lang.StringUtils;

import com.gooseeker.modbus.bean.ComUserData;

public class CmdUtils
{
	/**
	 * 测试设备是否连通
	 */
	private static final String CMD_TEST_DEVICE = "30 00 00 00 01 55";
	/**
	 * 测试设备连通ACK
	 */
	public static final String CMD_TEST_DEVICE_ACK = "30 01 AA";
	/**
	 * 读取设备序列号（全局唯一地址：7字节）
	 */
	private static final String CMD_READ_SNO = "35 00 00 00 07";
	/**
	 * 读取8路采集数据值
	 */
	private static final String CMD_READ_ALL_DATA = "04 00 00 00 08";
	/**
	 * 读取某一路数据值
	 * 格式：addr 04 regh regl numh numl crch crcl
	 */
	private static final String CMD_READ_CHANNEL_DATA = "04 00";
	/**
	 * 设置从机地址
	 */
	private static final String CMD_SET_SLAVE_ADDR = "32 00 01 00 01 01";
	/**
	 * 设置从机通信波特率
	 */
	private static final String CMD_SET_BUAD_RATE = "32 00 00 00 01 01";
	/**
	 * 设置用户数据，长度16位
	 */
	private static final String CMD_PUT_USER_DATA = "33 00 00 00";
	/**
	 * 获取用户数据，长度16位
	 */
	private static final String CMD_GET_USER_DATA = "34 00 00 00";

	/**
	 * 根据地址组装命令
	 * @param addr 设备地址，如1，2，3，4...
	 * @return 命令
	 */
	public static byte[] testDevice(int addr)
	{
		String cmd = getCmd(addr, ConstValue.MODBUS_TEST_DEVICE, null);

		if (StringUtils.isEmpty(cmd))
		{
			return null;
		}

		return CRC16Utils.modbusCrc16(cmd);
	}
	/**
	 * 读取设备唯一序列号（7字节）
	 * @param addr
	 * @return
	 */
	public static byte[] getDeviceSno(int addr)
	{
		String cmd = getCmd(addr, ConstValue.MODBUS_READ_SNO, null);

		if (StringUtils.isEmpty(cmd))
		{
			return null;
		}

		return CRC16Utils.modbusCrc16(cmd);
	}
	
	/**
	 * 读取所有数据
	 * @param addr
	 * @return
	 */
	public static byte[] readData(int addr)
	{
		String cmd = getCmd(addr, ConstValue.MODBUS_READ_ALL_DATA, null);

		if (StringUtils.isEmpty(cmd))
		{
			return null;
		}

		return CRC16Utils.modbusCrc16(cmd);
	}
	
	public static byte[] readDataByChannel(int addr, ComUserData channel)
	{
		String cmd = getCmd(addr, ConstValue.MODBUS_READ_DATA_BY_CHANNEL, channel);

		if (StringUtils.isEmpty(cmd))
		{
			return null;
		}
		
		return CRC16Utils.modbusCrc16(cmd);
	}
	/**
	 * 设置从机地址
	 * @param addr 从机当前地址
	 * @param newAddr 从机新地址
	 * @return
	 */
	public static byte[] setSlaveAddr(int addr, ComUserData newAddr)
	{
		String cmd = getCmd(addr, ConstValue.MODBUS_MOD_SLAVE_ADDR, newAddr);
		
		if (StringUtils.isEmpty(cmd))
		{
			return null;
		}
		
		return CRC16Utils.modbusCrc16(cmd);
	}
	/**
	 * 设置波特率
	 * @param addr
	 * @param buadRate 取值见ConstValue.COM_BUAD_RATE_****
	 * @return
	 */
	public static byte[] setBuadrate(int addr, int buadRate)
	{
		ComUserData data = new ComUserData();
		data.setData(Integer.toString(buadRate));
		String cmd = getCmd(addr, ConstValue.MODBUS_MOD_BUAD_RATE, data);
		
		if (StringUtils.isEmpty(cmd))
		{
			return null;
		}
		
		return CRC16Utils.modbusCrc16(cmd);
	}
	/**
	 * 存储用户数据
	 * @param addr
	 * @param data
	 * @return
	 */
	public static byte[] setUserData(int addr, ComUserData data)
	{
		String cmd = getCmd(addr, ConstValue.MODBUS_PUT_USER_DATA, data);
		
		if (StringUtils.isEmpty(cmd))
		{
			return null;
		}
		
		return CRC16Utils.modbusCrc16(cmd);
	}
	
	public static byte[] getUserData(int addr, int len)
	{
		ComUserData data = new ComUserData();
		data.setLen(len);
		String cmd = getCmd(addr, ConstValue.MODBUS_GET_USER_DATA, data);
		
		if (StringUtils.isEmpty(cmd))
		{
			return null;
		}
		
		return CRC16Utils.modbusCrc16(cmd);
	}
	
	/**
	 * 构造命令
	 * @param addr 从机地址
	 * @param cmd 命令
	 * @param data 用户数据
	 * @return
	 */
	private static String getCmd(int addr, int cmd, ComUserData data)
	{
		if (isAddrIllegal(addr))
		{
			return null;
		}

		StringBuffer sb = new StringBuffer();
		sb.append(CRC16Utils.intToHexStr(addr));
		sb.append(" ");

		switch (cmd)
		{
		case ConstValue.MODBUS_TEST_DEVICE:
			sb.append(CMD_TEST_DEVICE);
			break;

		case ConstValue.MODBUS_READ_SNO:
			sb.append(CMD_READ_SNO);
			break;

		case ConstValue.MODBUS_READ_ALL_DATA:
			sb.append(CMD_READ_ALL_DATA);
			break;
			
		case ConstValue.MODBUS_MOD_SLAVE_ADDR:
			sb.append(CMD_SET_SLAVE_ADDR);
			sb.append(" ");
			sb.append(getSubAddr(data.getData()));
			break;
			
		case ConstValue.MODBUS_MOD_BUAD_RATE:
			sb.append(CMD_SET_BUAD_RATE);
			sb.append(" ");
			sb.append(getBuadrate(data.getData()));
			break;
			
		case ConstValue.MODBUS_PUT_USER_DATA:
			sb.append(CMD_PUT_USER_DATA);
			sb.append(" ");
			sb.append(CRC16Utils.intToHexStr(data.getLen()));
			sb.append(" ");
			sb.append(CRC16Utils.intToHexStr(data.getLen()));
			sb.append(" ");
			for (int i = 0; i < data.getLen(); i++)
			{
				
				sb.append(CRC16Utils.intToHexStr(data.getData().charAt(i)));
				sb.append(" ");
			}
			sb.deleteCharAt(sb.length() - 1);
			break;
			
		case ConstValue.MODBUS_GET_USER_DATA:
			sb.append(CMD_GET_USER_DATA);
			sb.append(" ");
			sb.append(CRC16Utils.intToHexStr(data.getLen()));
			
			break;
			
		//addr 04 regh regl numh numl crch crcl
		case ConstValue.MODBUS_READ_DATA_BY_CHANNEL:
			sb.append(CMD_READ_CHANNEL_DATA);
			sb.append(" ");
			sb.append(CRC16Utils.intToHexStr(data.getLen() - 1));
			sb.append(" ");
			sb.append("00 02");
			
			break;
			
		default:
			break;
		}

		return sb.toString();
	}
	
	private static String getBuadrate(String data)
	{
		return CRC16Utils.intToHexStr(Integer.valueOf(data));
	}
	
	private static String getSubAddr(String addr)
	{
		return CRC16Utils.intToHexStr(Integer.valueOf(addr));
	}
	
	/**
	 * 从机地址是否不合法
	 * @param addr
	 * @return true-不合法，false-合法
	 */
	private static boolean isAddrIllegal(int addr)
	{
		boolean ret = true;
		
		if (addr <= ConstValue.SLAVE_MAX_ADDR && addr >= ConstValue.SLAVE_MIN_ADDR)
		{
			ret = false;
		}
		
		return ret;
	}
	
	public static void main(String[] args)
	{
		ComUserData data = new ComUserData();
		data.setData("0123456789abcdef");
		data.setLen(2);
		//byte[] cmd = CmdUtils.setUserData(1, data);
		//String tString = CRC16Utils.intToHexStr(Integer.valueOf("127"));
		//System.out.println(tString);
		
		System.out.println(getCmd(5, ConstValue.MODBUS_READ_DATA_BY_CHANNEL, data));
		System.out.println(ByteUitls.printByteArray(readDataByChannel(1, data), 6));
	}
}
